using UnityEngine;
using System.Collections;
using System.Collections.Generic;

public partial class CharacterSheet : LoadableJSONObject{
	
	Dictionary<string, Dictionary<string, List<TemporaryBonus>>> _buffsDatabase;
	Dictionary<string, Dictionary<string, List<TemporaryBonus>>> buffsDatabase
	{
		get
		{
			if(_buffsDatabase == null)
				_buffsDatabase = new Dictionary<string, Dictionary<string, List<TemporaryBonus>>>();
			
			return _buffsDatabase;
		}
		set
		{
			_buffsDatabase = value;
		}
	}
	
	//Returns a Dictionary of Lists of Bonuses to the stat in question Keyed by the modifier type
	//Only includes the highest value of all positive bonuses in index 0, includes every die and negative bonus later in the list
	public Dictionary<string, List<TemporaryBonus>> GetBuffMods(string stat, string substat = null)
	{	
		if(!buffsDatabase.ContainsKey(stat+(substat==null?"":"_"+substat)))
		{
			List<string> statHierarchy;
			if(modificationHierarchy.ContainsKey(stat))
				statHierarchy = modificationHierarchy[stat];
			else
				statHierarchy = new List<string>{stat};
			
			Dictionary<string,List<TemporaryBonus>> statsDict = new Dictionary<string, List<TemporaryBonus>>();
			
			foreach(BuffDebuff buff in buffs)
			{
				if(!buff.active)
					continue;
				
				List<TemporaryBonus> correctStatBonuses = buff.modifiers.FindAll(m => statHierarchy.Contains(m.toStat));
				
				if(correctStatBonuses.Count > 0)
				{
					
					List<TemporaryBonus> FlatBonuses = correctStatBonuses.FindAll(m => m.dicep == 0 && m.amount >= 0);
				
					foreach(TemporaryBonus bonus in FlatBonuses)
					{
						if(bonus.toStat == stat)
						{
							if(substat != null && bonus.subStat != substat)
								continue;
						}
						if(!statsDict.ContainsKey(bonus.type))
						{
							statsDict.Add(bonus.type, new List<TemporaryBonus>());
							statsDict[bonus.type].Add(bonus);
						}
						if(statsDict[bonus.type][0].amount < bonus.amount)
							statsDict[bonus.type][0] = bonus;
					}
					
					List<TemporaryBonus> FlatPenalties = correctStatBonuses.FindAll(m => m.dicep == 0 && m.amount < 0);
					
					foreach(TemporaryBonus bonus in FlatPenalties)
					{
						if(bonus.toStat == stat)
						{
							if(substat != null && bonus.subStat != substat)
								continue;
						}
						if(!statsDict.ContainsKey(bonus.type))
						{
							statsDict.Add(bonus.type, new List<TemporaryBonus>());
						}
						statsDict[bonus.type].Add(bonus);
					}
					
					List<TemporaryBonus> dieBonuses = correctStatBonuses.FindAll(m => m.dicep > 0);
					
					foreach(TemporaryBonus bonus in dieBonuses)
					{
						if(bonus.toStat == stat)
						{
							if(substat != null && bonus.subStat != substat)
								continue;
						}
						if(!statsDict.ContainsKey(bonus.type))
						{
							statsDict.Add(bonus.type, new List<TemporaryBonus>());
						}
						statsDict[bonus.type].Add(bonus);
					}
					
				}
			}
			
			buffsDatabase.Add(stat+(substat==null?"":"_"+substat),statsDict);
		}
		
		return buffsDatabase[stat+(substat==null?"":"_"+substat)];
	}
	
	public void RefreshBuffsDatabase(List<BuffDebuff> buffs)
	{
		foreach(BuffDebuff buff in buffs)
		{
			foreach(TemporaryBonus mod in  buff.modifiers)
			{
				string substat = (mod.subStat=="None"?"":"_"+mod.subStat);
				if(buffsDatabase.ContainsKey(mod.toStat+substat))
					buffsDatabase.Remove(mod.toStat+(mod.subStat=="None"?"":"_"+substat));
			}
		}
	}
	
	public static List<string> validModifications = new List<string>{
		"AC", "All Ability Checks", "All Skill Checks", "Arcane Spell Failure", "Armor Check", "Attacks", "Charisma", "Charisma Checks", 
		"CMD", "Combat Maneuvers", "Constitution", "Constitution Checks", "Crit. Damage", "Damage", "Damage Reduction", "Dexterity", 
		"Dexterity Checks", "Fortitude", "Intelligence", "Intelligence Checks", "Max. Dex Bonus", "Max HP", "Melee Attacks", 
		"Ranged Attacks", "Reflex", "Saving Throws", "Skill", "Spell Resistance", "Speed", "Strength", 
		"Strength Checks", "Will", "Wisdom", "Wisdom Checks"
	};
	
	
	public static Dictionary<string,List<string>> modificationHierarchy = new Dictionary<string, List<string>>(){
		{"Strength", new List<string>{"Strength"}},
		{"Dexterity", new List<string>{"Dexterity"}},
		{"Constitution", new List<string>{"Constitution"}},
		{"Intelligence", new List<string>{"Intelligence"}},
		{"Wisdom", new List<string>{"Wisdom"}},
		{"Charisma", new List<string>{"Charisma"}},
		{"Strength Checks", new List<string>{"Strength Checks","All Ability Checks"}},
		{"Dexterity Checks", new List<string>{"Dexterity Checks","All Ability Checks"}},
		{"Constitution Checks", new List<string>{"Constitution Checks","All Ability Checks"}},
		{"Intelligence Checks", new List<string>{"Intelligence Checks","All Ability Checks"}},
		{"Wisdom Checks", new List<string>{"Wisdom Checks","All Ability Checks"}},
		{"Charisma Checks", new List<string>{"Charisma Checks","All Ability Checks"}},
		{"Attacks", new List<string>{"Attacks","All Ability Checks"}},
		{"Melee Attacks", new List<string>{"Attacks","Melee Attacks","All Ability Checks"}},
		{"Ranged Attacks", new List<string>{"Attacks","Ranged Attacks","All Ability Checks"}},
		{"AC", new List<string>{"AC"}},
		{"Saving Throws", new List<string>{"Saving Throws","All Ability Checks"}},
		{"Fortitude", new List<string>{"Fortitude","Saving Throws","All Ability Checks"}},
		{"Reflex", new List<string>{"Reflex","Saving Throws","All Ability Checks"}},
		{"Will", new List<string>{"Will","Saving Throws","All Ability Checks"}},
		{"Damage", new List<string>{"Damage"}},
		{"Skill Checks", new List<string>{"Skill Checks","All Ability Checks"}},
		{"All Ability Checks", new List<string>{"All Ability Checks"}},
		{"Max HP", new List<string>{"Max HP"}},
		{"Combat Maneuvers", new List<string>{"Combat Maneuvers","All Ability Checks"}},
		{"Crit. Damage", new List<string>{"Crit. Damage"}},
		{"Skill", new List<string>{"Skill", "Skill Checks"}},
		{"CMD", new List<string>{"CMD"}}
	};
	
	public List<BuffDebuff> _buffs = new List<BuffDebuff>{};
	
	public List<BuffDebuff> _storedBuffs;
	
	public List<BuffDebuff> buffs
	{
		get
		{
			if(_storedBuffs == null)
			{
				List<BuffDebuff> b = new List<BuffDebuff>();
				b.AddRange(_buffs);
				
				foreach(InventoryItem item in equippedItems)
					b.AddRange(item.buffs);
				
				foreach(WeaponItem item in weapons)
				{
					if(item.currentlyDrawn)
						b.AddRange(item.buffs);
				}
				
				foreach(Ability a in Feats)
				{
					b.AddRange(a.buffs);
				}
				
				foreach(Ability a in specialAbility)
				{
					b.AddRange(a.buffs);
				}
				
				_storedBuffs = b;
			}
			
			return _storedBuffs;
		}
	}
	
	int _Strength = 10;
	public Dictionary<string,int> StrengthMods
	{
		get{
			Dictionary<string,int> statsDict = GetBuffMods("Strength").SubTotals();
			statsDict.Add("base", _Strength);
			
			return statsDict;
		}
	}
	public int Strength
	{
		get
		{
			int total = 0;
			foreach(int v in StrengthMods.Values){total += v;}
			total += race.STRMod;
			return total;
		}
	}
	public Dictionary<string,int> StrengthCheckMods
	{
		get{
			Dictionary<string,int> statsDict = GetBuffMods("Strength Checks").SubTotals();
			statsDict.Add("base", Strength.Modifier());
			
			return statsDict;
		}
	}
	public int StrengthModifier
	{
		get
		{
			int total = 0;
			foreach(int v in StrengthCheckMods.Values){total += v;}
			return total;
		}
	}
	
	int _Dexterity = 10;
	public Dictionary<string,int> DexterityMods
	{
		get{
			Dictionary<string,int> statsDict = GetBuffMods("Dexterity").SubTotals();
			statsDict.Add("base", _Dexterity);

			return statsDict;
		}
	}
	public int Dexterity
	{
		get
		{
			int total = 0;
			foreach(int v in DexterityMods.Values){total += v;}
			total += race.DEXMod;
			return total;
		}
	}
	public Dictionary<string,int> DexterityCheckMods
	{
		get{
			Dictionary<string,int> statsDict = GetBuffMods("Dexterity Checks").SubTotals();
			
			
			
			statsDict.Add("base", Dexterity.Modifier());
			
			return statsDict;
		}
	}
	public int DexterityModifier
	{
		get
		{
			int total = 0;
			foreach(int v in DexterityCheckMods.Values){total += v;}
			
			total = Mathf.Min(total, MaxDex);
			
			return total;
		}
	}
	
	public int _Constitution = 10;
	public Dictionary<string,int> ConstitutionMods
	{
		get{
			Dictionary<string,int> statsDict = GetBuffMods("Constitution").SubTotals();
			statsDict.Add("base", _Constitution);
			
			return statsDict;
		}
	}
	public int Constitution
	{
		get
		{
			int total = 0;
			foreach(int v in ConstitutionMods.Values){total += v;}
			total += race.CONMod;
			return total;
		}
	}
	public Dictionary<string,int> ConstitutionCheckMods
	{
		get{
			Dictionary<string,int> statsDict = GetBuffMods("Constitution Checks").SubTotals();
			statsDict.Add("base", Constitution.Modifier());
			
			return statsDict;
		}
	}
	public int ConstitutionModifier
	{
		get
		{
			int total = 0;
			foreach(int v in ConstitutionCheckMods.Values){total += v;}
			return total;
		}
	}
	
	public int _Intelligence = 10;
	public Dictionary<string,int> IntelligenceMods
	{
		get{
			Dictionary<string,int> statsDict = GetBuffMods("Intelligence").SubTotals();
			statsDict.Add("base", _Intelligence);
			
			return statsDict;
		}
	}
	public int Intelligence
	{
		get
		{
			int total = 0;
			foreach(int v in IntelligenceMods.Values){total += v;}
			total += race.INTMod;
			return total;
		}
	}
	public Dictionary<string,int> IntelligenceCheckMods
	{
		get{
			Dictionary<string,int> statsDict = GetBuffMods("Intelligence Checks").SubTotals();
			statsDict.Add("base", Intelligence.Modifier());
			
			return statsDict;
		}
	}
	public int IntelligenceModifier
	{
		get
		{
			int total = 0;
			foreach(int v in IntelligenceCheckMods.Values){total += v;}
			return total;
		}
	}
	
	public int _Wisdom = 10;
	public Dictionary<string,int> WisdomMods
	{
		get{
			Dictionary<string,int> statsDict = GetBuffMods("Wisdom").SubTotals();
			statsDict.Add("base", _Wisdom);
			
			return statsDict;
		}
	}
	public int Wisdom
	{
		get
		{
			int total = 0;
			foreach(int v in WisdomMods.Values){total += v;}
			total += race.WISMod;
			return total;
		}
	}
	public Dictionary<string,int> WisdomCheckMods
	{
		get{
			Dictionary<string,int> statsDict = GetBuffMods("Wisdom Checks").SubTotals();
			statsDict.Add("base", Wisdom.Modifier());
			
			return statsDict;
		}
	}
	public int WisdomModifier
	{
		get
		{
			int total = 0;
			foreach(int v in WisdomCheckMods.Values){total += v;}
			return total;
		}
	}
	
	public int _Charisma = 10;
	public Dictionary<string,int> CharismaMods
	{
		get{
			Dictionary<string,int> statsDict = GetBuffMods("Charisma").SubTotals();
			statsDict.Add("base", _Charisma);
			
			return statsDict;
		}
	}
	public int Charisma
	{
		get
		{
			int total = 0;
			foreach(int v in CharismaMods.Values){total += v;}
			total += race.CHAMod;
			return total;
		}
	}
	public Dictionary<string,int> CharismaCheckMods
	{
		get{
			Dictionary<string,int> statsDict = GetBuffMods("Charisma Checks").SubTotals();
			statsDict.Add("base", Charisma.Modifier());
			
			return statsDict;
		}
	}
	public int CharismaModifier
	{
		get
		{
			int total = 0;
			foreach(int v in CharismaCheckMods.Values){total += v;}
			return total;
		}
	}
	
	public bool SetStat(string stat, string value)
	{
		int i;
		if(int.TryParse(value, out i) && i < 600)
		{
			switch(stat)
			{
			case "Strength":
				_Strength = i;
				break;
			case "Dexterity":
				_Dexterity = i;
				break;
			case "Constitution":
				_Constitution = i;
				break;
			case "Intelligence":
				_Intelligence = i;
				break;
			case "Wisdom":
				_Wisdom = i;
				break;
			case "Charisma":
				_Charisma = i;
				break;
			}
			return true;
		}
		return false;
	}
	
	public void SetMathParserStats()
	{
		MathParser.SetVariable("Strength", StrengthModifier);
		MathParser.SetVariable("Dexterity", DexterityModifier);
		MathParser.SetVariable("Constitution", ConstitutionModifier);
		MathParser.SetVariable("Intelligence", IntelligenceModifier);
		MathParser.SetVariable("Wisdom", WisdomModifier);
		MathParser.SetVariable("Charisma", CharismaModifier);
		MathParser.SetVariable("BAB", BAB);
		MathParser.SetVariable("RangedAB", RangedAB);
		MathParser.SetVariable("MeleeAB", MeleeAB);
		MathParser.SetVariable("CMB", CMB);
		MathParser.SetVariable("Level", Level);
		
		foreach(CharacterClass c in classes)
		{
			MathParser.SetVariable(c.name+"_LVL", c.level);
		}
	}
}
